package com.fit.utils.se;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 反射工具类
 * @author hcl
 *
 */
public class ReflectUtil {
	private static Logger log = LoggerFactory.getLogger(ReflectUtil.class);
	
	//********************************************************
	//  内省操作(遵循了bean规范类的操作) start
	//********************************************************
	
	/**
	 * 执行bean 属性的get方法
	 * @param bean bean对象
	 * @param propertyName 属性名称
	 * @return 返回调用get方法后的返回值,异常时返回null
	 */
	public static Object executeGet(Object bean,String propertyName){
		Object result = null;
		if(EmptyUtils.isNotEmptys(bean,propertyName)){
			try {
				PropertyDescriptor pt = new PropertyDescriptor(propertyName, bean.getClass());
				Method methodGet = pt.getReadMethod();
				result = methodGet.invoke(bean);
			} catch (Exception e) {
				throw new RuntimeException("执行bean 属性的get方法异常！", e);
			}
		}
		return result;
	}
	
	/**
	 * 执行bean 属性的set方法
	 * @param bean bean对象
	 * @param propertyName 属性名称
	 * @param parameter 需要给set方法传入的参数
	 * @return
	 */
	public static void executeSet(Object bean,String propertyName,Object parameter){
		if(EmptyUtils.isNotEmptys(bean,propertyName)){
			try {
				PropertyDescriptor pt = new PropertyDescriptor(propertyName, bean.getClass());
				Method methodSet = pt.getWriteMethod();
				methodSet.invoke(bean,parameter);
			} catch (Exception e) {
				throw new RuntimeException("执行bean 属性的set方法异常！", e);
			}
		}
	}
	
	/**
	 * 获取bean 属性的get方法
	 * @param clazz bean对象的class
	 * @param propertyName 属性名称
	 * @return 返回bean 属性的get方法,异常返回null
	 */
	public static Method getMethodGet(Class<?> clazz,String propertyName){
		Method result = null;
		if(EmptyUtils.isNotEmptys(clazz,propertyName)){
			try{
				result = new PropertyDescriptor(propertyName, clazz).getReadMethod();
			} catch (Exception e) {
				throw new RuntimeException("获取bean 属性的get方法异常！", e);
			}
		}
		return result;
	}
	
	/**
	 * 获取bean 属性的set方法
	 * @param clazz bean对象的class
	 * @param propertyName 属性名称
	 * @return 返回bean 属性的set方法,异常返回null
	 */
	public static Method getMethodSet(Class<?> clazz,String propertyName){
		Method result = null;
		if(EmptyUtils.isNotEmptys(clazz,propertyName)){
			try{
				result = new PropertyDescriptor(propertyName, clazz).getReadMethod();
			} catch (Exception e) {
				throw new RuntimeException("获取bean 属性的set方法异常！", e);
			}
		}
		return result;
	}
	
	
	//********************************************************
	//  内省操作(遵循了bean规范类的操作) end
	//********************************************************
	
	//********************************************************
	//  获取和执行Method、Field start
	//********************************************************
	
	/**
	 * 根据方法名称和方法参数类型获取Method对象
	 * @param clazz Class对象
	 * @param methodName 方法名称
	 * @param parameterTypes 参数类型集合
	 * @return
	 */
	public static Method getMethod(Class<?> clazz,String methodName,Class<?>... parameterTypes){
		Method result = null;
		if(EmptyUtils.isNotEmptys(clazz, methodName)){
			try {
				try{
					result = clazz.getMethod(methodName, parameterTypes);
				}catch(NoSuchMethodException e){
				}
				if(EmptyUtils.isEmpty(result)){
					result = clazz.getDeclaredMethod(methodName, parameterTypes);
				}
			} catch(NoSuchMethodException e) {
				log.warn("在 {} 类中,没有找到 名为：{},参数:{} 的方法！",clazz.getName(),methodName,parameterTypes);
			}
		}
		return  result;
	}
	
	
	/**
	 * 获取属性名称获取Field对象
	 * @param clazz Class对象
	 * @param propertyName 属性名称
	 * @return
	 */
	public static Field getField(Class<?> clazz,String propertyName){
		Field result = null;
		if(EmptyUtils.isNotEmptys(clazz, propertyName)){
			try {
				try{
					result = clazz.getField(propertyName);
				}catch(NoSuchFieldException e){
				}
				if(EmptyUtils.isEmpty(result)){
					result = clazz.getDeclaredField(propertyName);
				}
			} catch(NoSuchFieldException e) {
				log.warn("在 {} 类中,没有找到 名为：{} 的属性！",clazz.getName(),propertyName);
			}
		}
		return result;
	}
	
	
	/**
	 * 执行对象的method方法
	 * @param obj 需要被执行的对象
	 * @param method 需要被执行的方法对象
	 * @param parameters 参数
	 * @return 返回执行方法返回的参数
	 */
	public static Object executeMethod(Object obj, Method method,Object... parameters){
		Object result = null;
		if(EmptyUtils.isNotEmptys(obj, method)){
			try{
				if(!Modifier.isPublic(method.getModifiers())){
					method.setAccessible(true);
				}
				result = method.invoke(obj,parameters);
			} catch (Exception e) {
				throw new RuntimeException("执行对象的method方法异常！", e);
			}
		}
		return result;
	}
	
	
	/**
	 * 获取对象的Field属性的值
	 * @param obj 被操作的对象
	 * @param field 属性对象
	 * @return 返回属性的值
	 */
	public static Object executeField(Object obj,Field field){
		Object result = null;
		if(EmptyUtils.isNotEmptys(obj, field)){
			try{
				if(!Modifier.isPublic(field.getModifiers())){
					field.setAccessible(true);
				}
				result = field.get(obj);
			} catch (Exception e) {
				throw new RuntimeException("获取对象的Field属性的值异常！", e);
			}
		}
		return result;
	}
	
	/**
	 * 设置对象的Field属性的值
	 * @param obj 被操作的对象
	 * @param field 属性对象
	 * @param val 需要设置的值
	 */
	public static void executeField(Object obj,Field field,Object val){
		if(EmptyUtils.isNotEmptys(obj, field)){
			try{
				if(!Modifier.isPublic(field.getModifiers())){
					field.setAccessible(true);
				}
				field.set(obj, val);
			} catch (Exception e) {
				throw new RuntimeException("设置对象的Field属性的值异常！", e);
			}
		}
	}
	
	
	//********************************************************
	//  获取和执行Method、Field end
	//********************************************************
	
	
	//********************************************************
	//  反射获取注解 start,如果获取的是父类上的注解,那么这个注解必须加@Inherited
	//********************************************************
	
	/**
	 * 获取类上和父类上的所有注解(不包含接口)
	 * @param clazz 需要获取注释的class类
	 * @return 如果传入的clazz为null 则返回为null,否则返回clazz上的注释集合,就算clazz上没有注释,也会返回一个长度为0的数组
	 */
	public static Annotation[] getAnnotation(Class<?> clazz){
		Annotation[] result = null;
		if(EmptyUtils.isNotEmpty(clazz)){
			result = clazz.getAnnotations();
		}
		return result;
	}
	
	/**
	 * 获取类和父类上指定的注解(不包含接口)
	 * 如果获取的是父类上的注解,那么这个注解必须加@Inherited
	 * @param clazz 需要获取注释的class类
	 * @param annotationClass 指定需要被获取的注释
	 * @return 
	 */
	public static <T extends Annotation> T getAnnotation(Class<?> clazz,Class<T> annotationClass){
		T result = null;
		if(EmptyUtils.isNotEmptys(clazz,annotationClass) && clazz.isAnnotationPresent(annotationClass)){
			result = clazz.getAnnotation(annotationClass);
		}
		return result;
	}
	
	
	/**
	 * 获取类上和父类上的所有注解(包含所有的父接口)
	 * 如果获取的是父类上的注解,那么这个注解必须加@Inherited
	 * @param clazz 需要获取注释的class类
	 * @return
	 */
	public static Annotation[] getClassAndInterfacesAnnotation(Class<?> clazz){
		Map<String, Annotation> result = new HashMap<String, Annotation>();
		if(EmptyUtils.isNotEmpty(clazz)){
			Annotation[] anns = clazz.getAnnotations();
			for(Annotation ann : anns){
				String className = ann.getClass().getName();
				if(!result.containsKey(className)){
					result.put(className, ann);
				}
			}
			Class<?>[] interfaces = clazz.getInterfaces();
			for(Class<?> in : interfaces){
				anns = getClassAndInterfacesAnnotation(in);
				for(Annotation ann : anns){
					String className = ann.getClass().getName();
					if(!result.containsKey(className)){
						result.put(className, ann);
					}
				}
			}
		}
		Collection<Annotation> coll = result.values();
		return coll.toArray(new Annotation[coll.size()]);
	}
	
	
	/**
	 * 获取类和父类上指定的注解(包含所有的父接口)
	 * 如果获取的是父类上的注解,那么这个注解必须加@Inherited
	 * @param clazz 需要获取注释的class类
	 * @return
	 */
	public static <T extends Annotation> T getClassAndInterfacesAnnotation(Class<?> clazz,Class<T> annotationClass){
		T result = null;
		if(EmptyUtils.isNotEmptys(clazz,annotationClass)){
			if(clazz.isAnnotationPresent(annotationClass)){
				result = clazz.getAnnotation(annotationClass);
			}else{
				Class<?>[] interfaces = clazz.getInterfaces();
				for(Class<?> in : interfaces){
					result = getClassAndInterfacesAnnotation(in,annotationClass);
					if(result != null){
						break;
					}
				}
			}
		}
		return result;
	}
	
	
	
	
	/**
	 * 获取实现了AccessibleObject接口对象上所有的所有注解
	 * AccessibleObject的子类有：Field(字段对象), Method(方法对象), Constructor(构造方法对象), ReflectPermission(反射操作的 Permission 类)
	 * @param obj 被获取注解的对象
	 * @return
	 */
	public static Annotation[] getAnnotation(AccessibleObject obj){
		Annotation[] result = null;
		if(EmptyUtils.isNotEmpty(obj)){
			result = obj.getAnnotations();
		}
		return result;
	}
	
	/**
	 * 获取实现了AccessibleObject接口对象上指定的注解
	 * AccessibleObject的子类有：Field(字段对象), Method(方法对象), Constructor(构造方法对象), ReflectPermission(反射操作的 Permission 类)
	 * @param obj 被获取注解的对象
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 */
	public static <T extends Annotation> T getAnnotation(AccessibleObject obj,Class<T> annotationClass){
		T result = null;
		if(EmptyUtils.isNotEmptys(obj,annotationClass) && obj.isAnnotationPresent(annotationClass)){
			result = obj.getAnnotation(annotationClass);
		}
		return result;
	}

	/**
	 * 获取Method上指定的注解(包含所有的父接口)
	 * 查找路径：方法上->类上->父接口方法上->父接口上->一直向上找
	 * @param clazz class类对象
	 * @param method 方法对象
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 */
	public static <T extends Annotation> T getMethodInterfacesAnnotation(Class<?> clazz,Method method,Class<T> annotationClass){
		T result = null;
		if(EmptyUtils.isNotEmptys(clazz,method,annotationClass)){
			result =  getMethodInterfacesAnnotation(clazz,method.getName(), method.getParameterTypes(), annotationClass);
		}
		return result;
	}
	
	/**
	 * 获取Method上指定的注解(包含所有的父接口)
	 * 查找路径：方法上->类上->父接口方法上->父接口上->一直向上找
	 * @param clazz class类对象
	 * @param methodName 方法名称
	 * @param methodParameterTypes 参数类型数组
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 */
	private static <T extends Annotation> T getMethodInterfacesAnnotation(Class<?> clazz,String methodName,Class<?>[] methodParameterTypes,Class<T> annotationClass){
		T result = null;
		Method method = getMethod(clazz, methodName, methodParameterTypes);
		if(EmptyUtils.isNotEmpty(method)){
			//从方法上获取
			result = getAnnotation(method, annotationClass);
			if(EmptyUtils.isEmpty(result)){
				//从类上获取
				result = getAnnotation(clazz, annotationClass);
				if(EmptyUtils.isEmpty(result)){
					//从接口中方法或接口类中获取
					Class<?>[] ins = clazz.getInterfaces();
					for(Class<?> in : ins){
						result = getMethodInterfacesAnnotation(in, methodName, methodParameterTypes, annotationClass);
						if(EmptyUtils.isNotEmpty(result)){
							break;
						}
					}
				}
			}
		}
		return result;
	}
	
	/**
	 * 获取方法对象每个参数上所有的注解
	 * @param method 方法对象
	 * @return 返回一个二维数组,一维是每个参数的下标,二维是当前参数的多个注解
	 */
	public static Annotation[][] getMethodParameterAnnotations(Method method){
		Annotation[][] result = null;
		if(EmptyUtils.isNotEmpty(method)){
			result = method.getParameterAnnotations();
		}
		return result;
	}
	
	//********************************************************
	//  反射获取注解 end,如果获取的是父类上的注解,那么这个注解必须加@Inherited
	//********************************************************
	
	
}
